package cn.tedu.imop.common.aspect;


import cn.tedu.imop.api.domain.OperationLog;
import cn.tedu.imop.api.service.LogRemoteService;
import cn.tedu.imop.common.annotation.RequiredOperationLog;
import cn.tedu.imop.common.service.AsyncLogService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.implementation.bytecode.Throw;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Date;

@Slf4j
@Aspect
@Component
public class OperationLogAspect {

    private final AsyncLogService asyncLogService;
    public OperationLogAspect(AsyncLogService asyncLogService) {
        this.asyncLogService = asyncLogService;
    }
    @Pointcut("@annotation(cn.tedu.imop.common.annotation.RequiredOperationLog)")
    public void doLog(){}

    @Around("doLog()")
    public Object doAround(ProceedingJoinPoint joinPoint)throws Throwable{
        long time=0;
        int status=0;
        String message="";
        long start=System.currentTimeMillis();
        log.info("doAround.before"+ LocalDateTime.now());
        try {
            //调用目标执行链(其它切面+目标对象方法)
            Object result = joinPoint.proceed();
            log.info("doAround.after" + LocalDateTime.now());
            time = System.currentTimeMillis() - start;
            return result;
        }catch (Throwable e) {
           log.error("日志记录异常 {}",e);
           time = System.currentTimeMillis() - start;
           status=1;
           message=e.getMessage();
           throw e;
        }finally {
            saveOperationLog(joinPoint,status,message,time);
        }

    }
    private void saveOperationLog(ProceedingJoinPoint joinPoint,int status,String message,long time) throws NoSuchMethodException, JsonProcessingException {
        //1.获取目标类的字节码对象
        Class<?> targetCls=joinPoint.getTarget().getClass();
        //2.获取类中的方法签名对象
        MethodSignature ms=(MethodSignature) joinPoint.getSignature();
        //3.获取目标方法对象
        Method targetMethod =
                targetCls.getDeclaredMethod(
                        ms.getName(),//方法名
                        ms.getParameterTypes());//参数列表类型
        //4.获取方法上的RequiredOperationLog注解对象，并获取注解对象中value属性值
        RequiredOperationLog requiredOperationLog =
                targetMethod.getAnnotation(RequiredOperationLog.class);
        String operation=requiredOperationLog.value();
        //4.获取实际参数值并转换为json格式字符串
        String params=new ObjectMapper().writeValueAsString(joinPoint.getArgs());
        //将获取的日志通过远程service对象，写入到数据库
        OperationLog operationLog=new OperationLog();
        operationLog.setUsername("tony")
                .setIp("192.168.1.100")
                .setOperation(operation)
                .setMethod(targetCls.getName()+"."+targetMethod.getName())
                .setParams(params)
                .setStatus(status)
                .setError(message)
                .setTime(time);
        //方案1:远程服务调用
        asyncLogService.createOperationLog(operationLog);
       //方案2:写消息队列
        String jsonStr = new ObjectMapper().writeValueAsString(operationLog);
        rabbitTemplate.convertAndSend("imop.log.queue",jsonStr);
    }
    @Autowired
    private RabbitTemplate rabbitTemplate;

}
